﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using System.Windows.Threading;
using System.Windows.Media.Imaging;
using System.Net.Sockets;
using System.Xml.Serialization;
using System.IO;
using System.Collections.Generic;

namespace Tanks
{
    public class Bullet
    {
        int id = ++((App)Application.Current).Number_of_bullets;//уникальный идентификатор пули
        Tank tank;// танка, выпустивший пулю
        Direction course;//текущее направление движения пули
        Point position;//позиция пули на экране
        Ellipse el;//фигура нашей пули
        DispatcherTimer t;//таймер, асинхронно вызывающий метод, отвечающий за движение пули
        Polygon p ;//фигура взрыва

        int SPEED; //скорость движения пули

        public int Id
        {
            get { return id; }
        }

        public Point Position
        {
            get { return position; }
        }

        public Tank Source_tank
        {
            get { return tank; }
        }

        public Bullet(Tank ta,bool need_send)
        {
            tank = ta;
            course = ta.Course;
            if (course == Direction.Up)
            {
                position.X = ta.Position.X + 22.5;
                position.Y = ta.Position.Y -14;
            }
            if (course == Direction.Right)
            {
                position.X = ta.Position.X + 67;
                position.Y = ta.Position.Y + 21;
            }
            if (course == Direction.Down)
            {
                position.X = ta.Position.X + 32.5;
                position.Y = ta.Position.Y + 66;
            }
            if (course == Direction.Left)
            {
                position.X = ta.Position.X - 12.5;
                position.Y = ta.Position.Y + 31.5;
            }
            SPEED = ta.Speed_bullet;
            ((App)Application.Current).Bullets.Add(this);
            draw();
            if(need_send==true)
                send_bullet_info();
            t = new DispatcherTimer();
            t.Interval = new TimeSpan(0, 0, 0, 0, 5);
            t.Tick += new EventHandler(fly);
            t.Start();
        }

        void draw()//прорисовка пули
        {
            el = new Ellipse();
            el.Height = 10;
            el.Width = 7;
            if (tank.Team == Colors.Blue)
            {
                el.Stroke = new SolidColorBrush(Colors.Black);
                el.Fill = new SolidColorBrush(Colors.Blue);
            }
            else
            {
                el.Stroke = new SolidColorBrush(Colors.Black);
                el.Fill = new SolidColorBrush(Colors.Orange);
            }
            ((App)Application.Current).Main_canvas.Children.Add(el);
            Canvas.SetLeft(el, Position.X);
            Canvas.SetTop(el, Position.Y);
            if (course == Direction.Right || course == Direction.Left)
                el.Projection = prepare_pojection(90);
        }

        PlaneProjection prepare_pojection(int angle)// функция возвращает объект преобразования, используя угол поворота 
        {
            PlaneProjection pl = new PlaneProjection();
            pl.CenterOfRotationX = 0.5;
            pl.CenterOfRotationY = 0.5;
            pl.CenterOfRotationZ = 0.5;
            pl.RotationZ = 360 - angle;
            return pl;
        }

        void fly(object sender, EventArgs e)//метод, вызываемый таймером. Меняет  координату пули
        {
            Tank t;
            if (course == Direction.Up)
            {
                position.Y -= SPEED;
                if (define_wall_point() == true)
                {
                    timer_stop();
                    return;
                }
                if ((t = define_tank_point()) != null)
                {
                    t.increase_damage(this);
                    timer_stop();
                    return;
                }
            }
            if (course == Direction.Down)
            {
                position.Y += SPEED;
                if (define_wall_point() == true)
                {
                    timer_stop();
                    return;
                }
                if ((t = define_tank_point()) != null)
                {
                    t.increase_damage(this);
                    timer_stop();
                    return;
                }
            }
            if (course == Direction.Right)
            {
                position.X += SPEED;
                if (define_wall_point() == true)
                {
                    timer_stop();
                    return;
                }
                if ((t = define_tank_point()) != null)
                {
                    t.increase_damage(this);
                    timer_stop();
                    return;
                }
            }
            if (course == Direction.Left)
            {
                position.X -= SPEED;
                if (define_wall_point() == true)
                {
                    timer_stop();
                    return;
                }
                if ((t = define_tank_point()) != null)
                {
                    t.increase_damage(this);
                    timer_stop();
                    return;
                }
            }
            if (position.X < 0 || position.X > 735 || position.Y < 0 || position.Y > 585)
            {
                timer_stop();
                return;
            }
            refresh();
        }

        


        public void refresh()//обновляет кординату пули на экране
        {
            Canvas.SetTop(el, position.Y);
            Canvas.SetLeft(el, position.X);
        }

        void timer_stop()//останавливает движение пули
        {
            t.Stop();
            ((App)Application.Current).Main_canvas.Children.Remove(el);
            ((App)Application.Current).Number_of_bullets--;
            ((App)Application.Current).Bullets.Remove(this);
            p=prepare_bang_polygon();//подготовка полигона для взрыва
            ((App)Application.Current).Main_canvas.Children.Add(p);
            double popX=0, popY=0;//поправки на отображение взрывов
            switch (course)
            {
                case Direction.Up: { popY = -14; popX = -14; break; }
                case Direction.Down: { popY = -14; popX = -14; break; }
                case Direction.Left: { popX = -14; popY = -14; break; }
                case Direction.Right: { popX = -14; popY = -14; break; }
            }
            Canvas.SetTop(p, position.Y+popY);
            Canvas.SetLeft(p, position.X+popX);
            t = new DispatcherTimer();
            t.Interval = new TimeSpan(0, 0, 0, 0, 150);
            t.Tick += new EventHandler(bang);
            t.Start();
        }

        Polygon prepare_bang_polygon()//подготавливает графику для взрыва
        {
            Polygon pol=new Polygon();
            pol.Height = 28;
            pol.Width = 27;
            PointCollection pc = new PointCollection();
            pc.Add(new Point(0,14));
            pc.Add(new Point(9,12));
            pc.Add(new Point(6,6));
            pc.Add(new Point(12,8));
            pc.Add(new Point(14,0));
            pc.Add(new Point(16,8));
            pc.Add(new Point(22,6));
            pc.Add(new Point(19,12));
            pc.Add(new Point(27,14));
            pc.Add(new Point(19,6));
            pc.Add(new Point(22,22));
            pc.Add(new Point(16,20));
            pc.Add(new Point(14,28));
            pc.Add(new Point(12,20));
            pc.Add(new Point(6,22));
            pc.Add(new Point(9,16));
            pol.Points = pc;
            ImageBrush im_br = new ImageBrush();
            im_br.ImageSource = new BitmapImage(new Uri("/Tanks;component/Images/bang.jpeg", UriKind.Relative));
            pol.Fill = im_br;

            return pol;
        }

        void bang(object sender, EventArgs e)//останавливает взрыв
        {
            t.Stop();
            ((App)Application.Current).Main_canvas.Children.Remove(p);            
        }

        bool define_wall_point()//анализирует попадание в стенку, и увеличивает ее повреждения
        {
            foreach (Wall w in ((App)Application.Current).map.List_of_walls)
            {
                if (course == Direction.Up)
                    if (position.X > w.Left_up.X && position.X < w.Right_down.X && position.Y > w.Left_up.Y && position.Y < w.Right_down.Y)
                    {
                        position.Y = w.Right_down.Y;
                        w.increase_damage(course);
                        return true;
                    }
                if (course == Direction.Right)
                    if (position.X > w.Left_up.X && position.X < w.Right_down.X && position.Y > w.Left_up.Y && position.Y < w.Right_down.Y)
                    {
                        position.X = w.Left_up.X;
                        w.increase_damage(course);
                        return true;
                    }
                if (course == Direction.Down)
                    if (position.X > w.Left_up.X && position.X < w.Right_down.X && position.Y > w.Left_up.Y && position.Y < w.Right_down.Y)
                    {
                        position.Y = w.Left_up.Y;
                        w.increase_damage(course);
                        return true;
                    }
                if (course == Direction.Left)
                    if (position.X > w.Left_up.X && position.X < w.Right_down.X && position.Y > w.Left_up.Y && position.Y < w.Right_down.Y)
                    {
                        position.X = w.Right_down.X;
                        w.increase_damage(course);
                        return true;
                    }
            }
            return false;
        }

        Tank define_tank_point()
        {
            foreach (Tank t in ((App)Application.Current).Tanks)
            {
                if (course == Direction.Up)
                {
                    if (position.X > t.Position.X && position.X < t.Position.X + 62 && position.Y > t.Position.Y && position.Y < t.Position.Y + 62)
                    {
                        position.Y = t.Position.Y + 62;
                        return t;
                    }
                }
                if (course == Direction.Right)
                {
                    if (position.X > t.Position.X && position.X < t.Position.X + 62 && position.Y > t.Position.Y && position.Y < t.Position.Y + 62)
                    {
                        position.X = t.Position.X;
                        return t;
                    }
                }
                if (course == Direction.Down)
                {
                    if (position.X > t.Position.X && position.X < t.Position.X + 62 && position.Y > t.Position.Y && position.Y < t.Position.Y + 62)
                    {
                        position.Y = t.Position.Y;
                        return t;
                    }
                }
                if (course == Direction.Left)
                {
                    if (position.X > t.Position.X && position.X < t.Position.X + 62 && position.Y > t.Position.Y && position.Y < t.Position.Y + 62)
                    {
                        position.X = t.Position.X + 62;
                        return t;
                    }
                }
            }
            return null;
        }

        void send_bullet_info()
        {
            if ((((App)Application.Current).Socket_app == null) || (((App)Application.Current).Socket_app.Connected == false))
            {
               // update("нет соединения");
                return;
            }
            SocketAsyncEventArgs args = new SocketAsyncEventArgs();

            PacketBullet pb = new PacketBullet();
            pb.Course = course;
            pb.Id = id;
            pb.Position = Position;
            pb.Id_tank = tank.ID;

            //создаем объект для сериализации 
            XmlSerializer serializer = new XmlSerializer(typeof(PacketBullet));
            //подготовка сообщения
            MemoryStream ms = new MemoryStream();

            //сериалиция объекта PaketTank в поток байтов
            serializer.Serialize(ms, pb);

            byte[] messageData = ms.ToArray();

            List<ArraySegment<byte>> bufferList = new List<ArraySegment<byte>>();
            bufferList.Add(new ArraySegment<byte>(messageData));
            args.BufferList = bufferList;

            ((App)Application.Current).Socket_app.SendAsync(args);
        }
    }
}